home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
1987
/
03
/
white.lst
< prev
Wrap
File List
|
1987-02-06
|
12KB
|
483 lines
/* Listing one */
/* Subroutines for converting a pixel image
to a quadtree and output the quadtree as
locational codes
Written by: Ronald G. White
External routines:
px2quad - only entry point
*/
#include <stdio.h>
/* Define structure for each node */
typedef struct qnode {
struct qnode *child[4]; /* pointers to each child */
struct qnode *next; /* used during output */
int color;
int ntype; /* see below for types */
int locode; /* location code */
} QNODE, *PNODE;
/* Node types: */
#define LEAF 1 /* no children */
#define BLEND 2 /* color of >2 kids */
#define WASH 3 /* color irrelevent */
extern getpix(); /* return pixel color at given posn */
extern putllc(); /* output location code and color */
static int toplevel; /* top level of tree (root node) */
px2quad(size)
int size;
/* entry point for these routines. Control routine to
create a quadtree from the pixel image and output it
as locational codes
input:
size - size of the image rounded up to nearest
power of two
*/
{
PNODE crtnode(), proot;
/* Create the root node */
proot = crtnode();
/* Calculate the toplevel number */
toplevel = 0;
while (size > 1) {
toplevel++;
size >>= 1; /* divide by two */
}
/* Build the quad tree */
proot->locode = 1;
addnode(proot, toplevel);
/* Output it as location codes */
outtree(proot);
}
static PNODE crtnode()
/* create a quadtree node and initialize it
output:
returns a pointer to the node
*/
{
int i;
PNODE newnode;
/* Get space for it */
newnode = (PNODE) malloc(sizeof(QNODE));
if (newnode == NULL) {
/* Something went wrong */
fprintf(stderr,
"crtnode: malloc failure; unable to continue0);
exit(1);
}
/* Initialize it */
for (i = 0; i < 4; i++) {
newnode->child[i] = NULL;
}
newnode->color = 0;
newnode->ntype = LEAF;
return(newnode);
}
static addnode(pnode, level)
int level;
PNODE pnode;
/* add a new node to the quad tree
If the node is not at the bottom level, four child
nodes are created and added below the current node.
Otherwise the node color is set to that of the
corresponding pixel.
input:
pnode - pointer to the current node
level - level number of the current node
*/
{
int i;
int newlevel;
PNODE crtnode(), newchild;
/* if this node is not at the bottom level,
* add four children below this node
*/
if (level > 0) {
newlevel = level - 1;
for (i = 0; i < 4; i++) {
newchild = crtnode();
pnode->child[i] = newchild;
newchild->locode = (pnode->locode << 2) + i;
addnode(newchild, newlevel);
}
/* Remove any unnecessary children */
condense(pnode);
/* bottom level; get actual pixel color */
} else {
pnode->color = getcolor(pnode->locode);
}
}
static condense(pnode)
PNODE pnode;
/* examine children of the current node and
remove any that are unnecessary
input:
pnode - pointer to current node
*/
{
int colcnt[4];
int colors[4];
int i, j;
int maxclr = 0;
int nkids;
int childclr;
PNODE pchild;
/* Initialization */
for (i = 0; i < 4; i++) {
colcnt[i] = 0;
}
/* Determine colors of children */
for (i = 0; i < 4; i++) {
pchild = pnode->child[i];
if (pchild->ntype == WASH) {
/* this child has no color */
continue;
}
childclr = pchild->color;
/* loop through colors found so far:
do we have a match?
note: we'll always "break" out of
this loop because there can be at
most four different colors.
*/
for (j = 0; j < 4; j++) {
if (colcnt[j] == 0) {
/* new color */
colors[j] = childclr;
colcnt[j] = 1;
break;
} else if (childclr == colors[j]) {
/* existing color */
colcnt[j]++;
if (colcnt[j] > colcnt[maxclr]) {
maxclr = j;
}
break;
}
}
}
/* Set node color */
pnode->color = colors[maxclr];
/* Remove redundant children -- if more than
one child node has the same color as the
current node, then it contains redundant
information. If the redundant node is a
leaf node, it can just be removed. If it
is not a leaf node, mark it as a WASH type
and ignore it during output.
*/
nkids = 4;
if (colcnt[maxclr] > 1) {
/* Loop through the four children */
for (i = 0; i < 4; i++) {
pchild = pnode->child[i];
/* If child node is already a WASH,
nothing else can be done to it
*/
if (pchild->ntype == WASH) {
continue;
}
childclr = pchild->color;
/* Check for color match */
if (childclr == pnode->color) {
/* If child is leaf, release */
if (pchild->ntype == LEAF) {
relnode(pchild);
pnode->child[i] = NULL;
nkids--;
/* otherwise, mark it as a WASH */
} else {
pchild->ntype = WASH;
}
}
}
}
/* Reset node type -- a LEAF node has no children */
if (nkids == 0) {
pnode->ntype = LEAF;
/* A BLEND node has a color that represents some
missing children, but still has some other
children that are a different color.
*/
} else if (colcnt[maxclr] > 1) {
pnode->ntype = BLEND;
/* A WASH node is necessary in the quadtree because
it points to existent children nodes, but will not
be output because its information (i.e. color) is
available either in child nodes or parent nodes.
*/
} else {
pnode->ntype = WASH;
}
}
relnode(pnode)
PNODE pnode;
/* release a node
input:
pnode - pointer to node to release
*/
{
free((char *) pnode);
}
static getcolor(lcode)
int lcode;
/* get the color of the pixel corresponding to a
bottom level node whose position is given by a
locational code
input:
lcode - locational code of bottom level node
output:
returns pixel color
*/
{
int dir;
int col = 0;
int level;
int row = 0;
int shift;
/* Convert node locational code to pixel row & column
by looping through direction codes in locational
code for each level from top to bottom
*/
for (level = toplevel; level > 0; level--) {
/* shift last row & col values left one bit */
col <<= 1;
row <<= 1;
/* calculate the position of the direction
code for this level and extract it
*/
shift = (level - 1) * 2;
dir = (lcode >> shift) & 0x3;
/* increment the col value if quadrant is in
left half, i.e. NE or SE child
*/
if (dir == 1 || dir == 3) {
col++;
}
/* increment the row value if quadrant is in
bottom half, i.e. SW or SE child
*/
if (dir == 2 || dir == 3) {
row++;
}
}
/* return pixel color */
return(getpix(col, row));
}
static outtree(proot)
PNODE proot;
/* output the relevant nodes in the quad tree
*
* proot - pointer to the root node
*/
{
PNODE outnode(), pcur, plast;
/* Set up the linked list with root node */
pcur = proot;
plast = proot;
proot->next = NULL;
/* Output each node on the linked list in order
until there are no more nodes on the list
*/
while (pcur != NULL) {
plast = outnode(pcur, plast);
pcur = pcur->next;
}
}
static PNODE outnode(pnode, plast)
PNODE pnode, plast;
/* output the locational code and color index for a
node and put its children on the list
input:
pnode - pointer to node to output
plast - pointer to last node on the linked list
output:
returns pointer to new last node on linked list
*/
{
int i;
PNODE pchild;
/* If node is not a WASH, output it */
if (pnode->ntype != WASH) {
putlcc(pnode->locode, pnode->color);
}
/* Put the node's children on list */
if (pnode->ntype != LEAF) {
for (i = 0; i < 4; i++) {
pchild = pnode->child[i];
if (pchild != NULL) {
plast->next = pchild;
plast = pchild;
}
}
}
/* Return new last pointer */
return(plast);
}
/* Listing two */
/* Subroutines for displaying an image from a quadtree
input as locational codes
Written by: Ronald G. White
External routines:
qdisp - only entry point
*/
#include <stdio.h>
extern getnxn(); /* read in next node's data */
extern filrec(); /* fill rectangular region */
static int orgsize; /* original image size */
qdisp(size)
int size;
/* main entry point for the display of a quadtree
*
* input:
* size - size of the original image
*/
{
int lcode, color;
int corner[2];
int side;
/* Make the image size global */
orgsize = size;
/* Read and display each node */
while (getnxn(&lcode, &color) != EOF) {
/* Convert loc code to corners, side of square */
square(lcode, corner, &side);
/* Fill in the square */
filrec(corner[0], corner[1], side, side, color);
}
}
square(lcode, corner, pside)
int lcode;
int corner[2];
int *pside;
/* convert quadtree locational code to corner and side
of the square represented by the corresponding node.
input:
lcode - locational code for this node
output:
corner - upper left corner of quadrant
pside - the size of the quadrant in pixels
*/
{
int dir;
int shift;
corner[0] = corner[1] = 0;
*pside = orgsize;
/* Find the begining of the code */
for (shift = 30;
((lcode >> shift) & 0xff) == 0; shift -= 2);
/* Convert node locational code to corner row &
column by looping through direction codes in
locational code for each level from top down.
*/
for (shift -= 2; shift >= 0; shift -= 2) {
/* The side of the square is reduced by a
factor of two each level down.
*/
*pside >>= 1;
/* extract the direction code */
dir = (lcode >> shift) & 0x3;
/* increment the col value if quadrant is
in left half, i.e. NE or SE child
*/
if (dir == 1 || dir == 3) {
corner[0] += *pside;
}
/* increment the row value if quadrant is
in bottom half, i.e. SW or SE child
*/
if (dir == 2 || dir == 3) {
corner[1] += *pside;
}
}
}